import { Button, NavBar, Form, Input, Toast } from 'antd-mobile'
import { InputRef } from 'antd-mobile/es/components/input'
import type { AxiosError } from 'axios'
import { useEffect, useRef, useState } from 'react'
import { useDispatch } from 'react-redux'
import { useHistory, useLocation } from 'react-router-dom'
import { login, getCode } from '@/store/actions/login'

import styles from './index.module.scss'

type LoginForm = { mobile: string; code: string }

const Login = () => {
  const location = useLocation<{ from: string } | undefined>()
  const history = useHistory()
  const dispatch = useDispatch()
  const [form] = Form.useForm()
  // 倒计时状态
  const [timeLeft, setTimeLeft] = useState(0)
  // 定时器 ref
  const timerRef = useRef(-1)

  // 创建获取手机号的 ref 对象
  // 注意：现在要操作的是 Input 组件，所以，此处的 泛型参数 应该组件的 ref 类型
  const mobileRef = useRef<InputRef>(null)

  // 登录
  // 默认 Form 并没有为 onFinish 指定 value 的类型，因为 Form 不清楚表单中处理的是什么数据
  // 所以，需要自己根据自己的 Form 表单项来手动指定 values 的类型即可
  const onFinish = async (values: LoginForm) => {
    try {
      await dispatch(login(values))

      // 登录成功后的操作
      Toast.show({
        content: '登录成功',
        duration: 800,
        afterClose: () => {
          history.replace(location.state?.from ?? '/home/index')
        }
      })
    } catch (e) {
      const error = e as AxiosError<{ message: string }>
      // console.log('登录失败')
      // console.dir(e)
      Toast.show({
        content: error.response?.data.message,
        duration: 1000
      })
    }
  }

  // 发送验证码
  const onGetCode = () => {
    // 如何获取 手机号 文本框的值？ 通过 Form 来获取
    // 参数表示 Form.Item name 属性
    // 注意： mobile 的值有可能是 undefined，所以，在类型断言的时候，也需要明确指出 undefined
    //  如果 手机号的文本框 还没有输入过内容，那么，值为：undefined
    //  如果 手机号的文本框 输入过内容，并且清空了，那么，值为：''
    // const mobile = form.getFieldValue('mobile') as string | undefined
    // console.log(mobile)
    // if (mobile === undefined || mobile.trim() === '') {
    //   return mobileRef.current?.focus()
    // }

    const mobile = (form.getFieldValue('mobile') ?? '') as string
    const hasError = form.getFieldError('mobile').length > 0
    if (mobile.trim() === '' || hasError) {
      return mobileRef.current?.focus()
    }

    // 表单验证成功，获取验证码
    // 发送请求，根据 手机号 来获取验证码
    dispatch(getCode(mobile))
    // 设置倒计时时间
    setTimeLeft(60)
    // 注意：此处需要明确指定 window.serInterval 表示使用的是浏览器环境中的定时器
    timerRef.current = window.setInterval(() => {
      setTimeLeft(timeLeft => timeLeft - 1)
    }, 1000)

    Toast.show({
      content: '验证码已发送',
      duration: 600
    })
  }

  useEffect(() => {
    // console.log('当前剩余时间：', timeLeft)
    if (timeLeft === 0) {
      // 清理定时器
      window.clearInterval(timerRef.current)
    }
    // 注意：不要在此处执行清理定时器 id，因为 timeLeft 作为 useEffect 的依赖项
    //      会导致，每次 timeLeft 改变时，都会执行一次清理操作。这会导致定时器
    //      不再执行。因此，不要在此处执行清理
    // return () => {
    //   // console.log('111')
    //   window.clearInterval(timerRef.current)
    // }
  }, [timeLeft])

  // 作用：在组件卸载时，清理定时器
  useEffect(() => {
    return () => {
      window.clearInterval(timerRef.current)
    }
  }, [])

  return (
    <div className={styles.root}>
      <NavBar onBack={() => history.go(-1)}></NavBar>

      <div className="login-form">
        <h2 className="title">账号登录</h2>

        <Form
          form={form}
          // validateTrigger={['onBlur']}
          onFinish={onFinish}
          initialValues={{
            // 注意 mobile 是字符串类型！！！
            mobile: '1391111222',
            code: '24681'
          }}
        >
          <Form.Item
            className="login-item"
            name="mobile"
            // validateTrigger="onBlur"
            rules={[
              {
                required: true,
                message: '请输入手机号'
              },
              {
                message: '手机号格式错误',
                pattern: /^1[3-9]\d{9}$/
              }
            ]}
          >
            <Input
              ref={mobileRef}
              placeholder="请输入手机号"
              autoComplete="off"
              maxLength={11}
            />
          </Form.Item>

          <Form.Item
            name="code"
            className="login-item"
            // validateTrigger="onBlur"
            extra={
              <span
                className="code-extra"
                onClick={timeLeft === 0 ? onGetCode : undefined}
              >
                {timeLeft === 0 ? '发送验证码' : `${timeLeft}s后重新获取`}
              </span>
            }
            rules={[
              { required: true, message: '请输入验证码' },
              {
                pattern: /^\d{6}$/,
                message: '验证码格式错误'
              }
            ]}
          >
            <Input
              placeholder="请输入验证码"
              autoComplete="off"
              maxLength={6}
            />
          </Form.Item>

          {/* noStyle 表示不提供 Form.Item 自带的样式 */}
          <Form.Item noStyle shouldUpdate>
            {() => {
              // isFieldsTouched(true) 用来判断登录表单中的所有表单项是否被操作过
              //  如果都操作过，结果为：true； 否则，为 false
              //  如果只看该判断项，如果为 true 表示操作过，此时，才可能是不禁用
              //                 如果为 false 表示没有操作过（没有输入过内容），就应该是禁用
              // console.log('登录按钮重新渲染了', form.isFieldsTouched(true))
              // console.log(form.getFieldsError())

              // 获取校验失败的表单项
              // const errors = form.getFieldsError().filter(item => item.errors.length > 0)

              // 如果需要获取 表单校验 是否成功，只需要获取上述 errors 数组的长度
              //  如果长度大于 0 说明有错误，表示：表单校验失败；否则，表单校验成功
              // console.log(
              //   form.getFieldsError().filter(item => item.errors.length > 0)
              // )

              // 得到禁用状态
              const disabled =
                form.getFieldsError().filter(item => item.errors.length > 0)
                  .length > 0 || !form.isFieldsTouched(true)

              return (
                <Button
                  disabled={disabled}
                  block
                  type="submit"
                  color="primary"
                  className="login-submit"
                >
                  登 录
                </Button>
              )
            }}
          </Form.Item>
        </Form>
      </div>
    </div>
  )
}

export default Login
